/* ========================================================================
 * PROJECT: FTIR Blob Tracker
 * ========================================================================
 * This work is based on the original FTIR Blob Tracker developed by
 *   Woonhyuk Baek
 *   Woontack Woo
 *   U-VR Lab, GIST of Gwangju in Korea.
 * 
 *   http://uvr.gist.ac.kr/
 *
 * Copyright of the derived and new portions of this work
 *     (C) 2009 GIST U-VR Lab.
 *
 * This framework is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This framework is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this framework; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * For further information please contact 
 *   Woonhyuk Baek
 *   <windage@live.com>
 *   GIST U-VR Lab.
 *   Department of Information and Communication
 *   Gwangju Institute of Science and Technology
 *   1, Oryong-dong, Buk-gu, Gwangju
 *   South Korea
 * ========================================================================
 ** @author   Woonhyuk Baek
 * ======================================================================== */

#ifndef _WARPPING_FRAMEWORK_H_
#define _WARPPING_FRAMEWORK_H_

#include <vector>

#include <cv.h>

#include "../Calibration/Calibration.h"
#include "../Calibration/Calibrator.h"
#include "../Calibration/Homography.h"
#include "../Warpping/Warpping.h"

namespace windage
{
	const int CHESSBOARD_WIDTH_COUNT = 7;
	const int CHESSBOARD_HEIGHT_COUNT = 8;
	const double CHESSBOARD_FIELD_SIZE = 28.0;

	class WarpFramework
	{
	private:
		const static int CONTROL_PRAMETER_COUNT = 4;
		
		int width;
		int height;
		int translationToCenterX;
		int translationToCenterY;
		windage::Matrix3 homography;

		std::vector<windage::Vector2> adjustmentParams;
		std::vector<windage::Vector2> imageParams;

		windage::Homography* homographyCalc;
		windage::Calibrator* calibrator;
		windage::Warpping* warpping;
		windage::Calibration* calibration;

		IplImage* tempImage;

		bool UpdateControlPoint();

	public:
		WarpFramework(int width, int height)
		{
			this->width = width;
			this->height = height;

			this->translationToCenterX = cvRound((double)width/2.0 - CHESSBOARD_FIELD_SIZE*CHESSBOARD_WIDTH_COUNT/2.0);
			this->translationToCenterY = cvRound((double)-height/2.0 + CHESSBOARD_FIELD_SIZE*CHESSBOARD_HEIGHT_COUNT/2.0);

			adjustmentParams.resize(CONTROL_PRAMETER_COUNT);
			imageParams.resize(CONTROL_PRAMETER_COUNT);
			imageParams[0].x = 0.0;		imageParams[0].y = 0.0;
			imageParams[1].x = width;	imageParams[1].y = 0.0;
			imageParams[2].x = width;	imageParams[2].y = height;
			imageParams[3].x = 0.0;		imageParams[3].y = height;

			homographyCalc = new windage::Homography(width, height);
			calibrator = new windage::Calibrator();
			warpping = new windage::Warpping();
			calibration = new windage::Calibration();

			tempImage = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
		}

		~WarpFramework()
		{
			if(homographyCalc) delete homographyCalc;
			if(calibrator) delete calibrator;
			if(warpping) delete warpping;
			if(calibration) delete calibration;

			if(tempImage) cvReleaseImage(&tempImage);
		}

		void Initialize(double fx, double fy, double cx, double cy, double d1=0.0, double d2=0.0, double d3=0.0, double d4=0.0)
		{
			this->calibration->Initialize(fx, fy, cx, cy, d1, d2, d3, d4);
			this->calibration->InitUndistortionMap(this->width, this->height);

			this->warpping->Initialize(this->width, this->height);
			this->warpping->AttatchCalibration(this->calibration);

			this->calibrator->Initialize(CHESSBOARD_WIDTH_COUNT, CHESSBOARD_HEIGHT_COUNT, CHESSBOARD_FIELD_SIZE);

			this->homographyCalc->SetFlip();
		}

		inline windage::Matrix3 GetHomography(){return this->homography;};
		void SetHomography(windage::Matrix3 h);

		int GetNearestPoint(windage::Vector2 point, double* distance);
		inline windage::Vector2 GetAdjustmentPoint(int index){return this->adjustmentParams[index];};
		inline void SetAdjustmentPoint(int index, windage::Vector2 point){this->adjustmentParams[index] = point;};
		inline void ResetAdjustmentPoints(){this->UpdateControlPoint();};
		void ChangeScaling(double scale = 1.0);
		void ChangeRotation(double radianAngle = 0.0);
		void ChangeTranslation(windage::Vector2 deltaT);
		
		bool WarpImageFromHomography(IplImage* src, IplImage* dst);
		bool UpdateHomographyFromChessboard(IplImage* src);
		bool UpdateHomographyFromPoints();
	};
}

#endif